package com.loong.game2048.module;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Random;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Game2048 implements Serializable {
    //游戏状态

    //游戏状态  0：开始   1：胜利  2：进行中   3：游戏结束  4：不能撤销
    private int gameState = 0;

    //最高分
    static int target = 2048;
    private int highest;
    private int score;


    //二维数组，用来存放格子
    private Tile[][] tiles;



    private int side = 4;

    //是否还可移动，若格子都满了，就不可以移动了
    private boolean checkingAvailableMoves;


    //开始游戏，初始化分数
    public void startGame() {
        if (gameState != 2) {
            score = 0;
            highest = 0;
            gameState = 2;
            //二维数组
            tiles = new Tile[side][side];
            //在数组中添加两个数字
            addRandomTile();
            addRandomTile();
        }
    }


    //添加数字
    private void addRandomTile() {
        Random rand = new Random();
        //在0~15中获取一个数字、确定位置
        int pos = rand.nextInt(side * side);
        //行、列
        int row, col;
        //找到空格子
        do {
            pos = (pos + 1) % (side * side);
            row = pos / side;
            col = pos % side;
        } while (tiles[row][col] != null);

        //新添加的数字只有 两种可能：4、2
        int val = rand.nextInt(10) == 0 ? 4 : 2;
        tiles[row][col] = new Tile(val);
    }

    /**
     * 移动方法
     * @param countDownFrom:从哪里开始遍历,如果是是向上移动，countDownFrom就是0
     * @param yIncr:要变化的y值
     * @param xIncr:要变化的x值
     * @return：是否移动过
     */
    private boolean move(int countDownFrom, int yIncr, int xIncr) {
        //是否已移动
        boolean moved = false;
        //遍历数组
        for (int i = 0; i < side * side; i++) {
            int j = Math.abs(countDownFrom - i);
            //行
            int r = j / side;
            //列
            int c = j % side;
            //格子为空，不做处理
            if (null == tiles[r][c] )
                continue;
            //要合并的行，如果是向上移动，yIncr的值是 -1,其它方法以此类推
            int nextR = r + yIncr;
            //要合并的列，如果是向上移动，xIncr的值是 0,其它方法以此类推
            int nextC = c + xIncr;

            while (nextR >= 0 && nextR < side && nextC >= 0 && nextC < side) {
                //要合并的格子
                Tile next = tiles[nextR][nextC];
                //当前格子
                Tile curr = tiles[r][c];

                //合并、移动
                if (next == null) {//直接移动
                    if (checkingAvailableMoves)
                        return true;
                    tiles[nextR][nextC] = curr;
                    tiles[r][c] = null;
                    r = nextR;
                    c = nextC;

                    //再判断能否继续移动
                    nextR += yIncr;
                    nextC += xIncr;
                    moved = true;
                } else if (next.canMergeWith(curr)) {//可合并
                    if (checkingAvailableMoves)
                        return true;
                    int value = next.mergeWith(curr);
                    if (value > highest)
                        highest = value;
                    //得分相加
                    score += value;
                    tiles[r][c] = null;
                    moved = true;
                    break;
                } else//不可合并
                    break;
            }
        }

        //移动过
        if (moved) {
            if (highest < target) {
                //把所有格子的合并标记置为false
                clearMerged();
                //添加一个格子
                addRandomTile();
                //不能再移动，游戏结束！！！！
                if (!movesAvailable()) {
                    gameState = 3;
                }
            } else if (highest == target)
                gameState = 1;
        }

        return moved;
    }

    //往上移，y值要减一，其它方法以此类推
    public boolean moveUp() {
        return move(0, -1, 0);
    }
    public boolean moveDown() {
        return move(side * side - 1, 1, 0);
    }
    public boolean moveLeft() {
        return move(0, 0, -1);
    }
    public boolean moveRight() {
        return move(side * side - 1, 0, 1);
    }

    //清除合并标记
    void clearMerged() {
        for (Tile[] row : tiles)
            for (Tile tile : row)
                if (tile != null)
                    tile.setMerged(false);
    }

    //判断还能否移动
    boolean movesAvailable() {
        //先把checkingAvailableMoves置为true，去判断一下游戏是否还能继续
        checkingAvailableMoves = true;
        boolean hasMoves = moveUp() || moveDown() || moveLeft() || moveRight();
        checkingAvailableMoves = false;
        return hasMoves;
    }

}

//格子对象
//class Tile {
//
//    private boolean merged;
//    private int value;
//    //构造方法
//    Tile(int val) {
//        value = val;
//    }
//    int getValue() {
//        return value;
//    }
//    void setMerged(boolean m) {
//        merged = m;
//    }
//
//
//    //判断能否合并
//    boolean canMergeWith(Tile other) {
//        //本身、other的merged标记都为flase,且值相同，才能合并
//        return !merged && other != null && !other.merged && value == other.getValue();
//    }
//
//    //合并
//    int mergeWith(Tile other) {
//        if (canMergeWith(other)) {
//            value *= 2;
//            merged = true;
//            return value;
//        }
//        return -1;
//    }
//}
